const { Op, where } = require("sequelize");
const { User: db, Role, UsersRoles, Menu } = require("../models");
const { NotFound, Conflict, BadRequest } = require("http-errors");
const { success } = require("../utils/response");
const { arrayToTree } = require("../utils");

class UserController {
  // 获取用户列表
  async getUsers(req, res, next) {
    try {
      const {
        username,
        phone,
        email,
        createdAt,
        updatedAt,
        pageSize,
        pageNum,
      } = req.query;
      const size = Math.abs(Number(pageSize)) || 15;
      const page = Math.abs(Number(pageNum)) || 1;
      const where = {};
      phone &&
        (where["phone"] = {
          [Op.eq]: phone,
        });
      email &&
        (where["email"] = {
          [Op.eq]: email,
        });
      username &&
        (where["username"] = {
          [Op.like]: `%${username}%`,
        });
      createdAt &&
        (where["createdAt"] = {
          [Op.between]: createdAt.split(","),
        });
      updatedAt &&
        (where["updatedAt"] = {
          [Op.between]: updatedAt.split(","),
        });
      const condition = {
        attributes: { exclude: ["password", "isDelete"] },
        order: [["updatedAt", "DESC"]],
        offset: (page - 1) * size,
        limit: size,
        where,
        include: {
          model: Role,
          as: "roles",
          attributes: ["name", "code"],
          through: {
            attributes: [],
          },
        },
      };
      const { count, rows } = await db.findAndCountAll(condition);
      success(res, "查询成功", {
        total: count,
        pageSize: size,
        pageNum: page,
        list: rows,
      });
    } catch (error) {
      next(error);
    }
  }
  // 获取指定用户
  async getUser(req, res, next) {
    try {
      const id = req.params.id;
      const user = await db.findOne({
        where: { id },
        attributes: { exclude: ["password"] },
        include: {
          model: Role,
          as: "roles",
          attributes: ["code"],
          through: {
            attributes: [],
          },
        },
      });
      if (!user) throw new NotFound("用户不存在");
      success(
        res,
        "查询成功",
        Object.assign(user.toJSON(), {
          roles: user.roles.map((item) => item.code),
        })
      );
    } catch (error) {
      next(error);
    }
  }
  // 添加用户
  async addUser(req, res, next) {
    try {
      const data = filterData(req.body);
      // 创建用户
      const user = await db.create(data);
      const roles = await getRoleIdByCode(req.body.roles);
      await UsersRoles.bulkCreate(
        roles.map(({ roleId }) => ({ userId: user.toJSON().id, roleId }))
      );
      success(res, "添加成功");
    } catch (error) {
      next(error);
    }
  }
  // 编辑用户
  async editUser(req, res, next) {
    try {
      const id = req.body.id;
      const user = await db.findOne({
        where: { id },
      });
      if (!user) throw new Conflict("用户不存在。");
      // 删除关系表中所有的关系
      await UsersRoles.destroy({
        where: {
          userId: id,
        },
      });
      // 通过传入字段查询对应code的id（roleId）
      const roles = await getRoleIdByCode(req.body.roles);
      // 批量创建用户角色关系
      await UsersRoles.bulkCreate(
        roles.map(({ roleId }) => ({ userId: id, roleId }))
      );

      const data = filterData(req.body);
      // 更新数据
      await user.update(data);
      success(res, "编辑成功");
    } catch (error) {
      next(error);
    }
  }
  // 删除用户
  async delUser(req, res, next) {
    try {
      const ids = req.query.ids
        .split(",")
        .map((id) => Number(id))
        .filter(Boolean);
      await UsersRoles.destroy({
        where: {
          userId: ids,
        },
      });
      await db.destroy({
        where: {
          id: ids,
        },
      });
      success(res, "删除成功");
    } catch (error) {
      next(error);
    }
  }

  // 获取用户菜单
  async getMenusByUserId(req, res, next) {
    try {
      const id = req.params.id;
      if (!id) throw new BadRequest("id不能为空");

      const user = await db.findOne({
        where: {
          id,
        },
        attributes: [],
        include: {
          model: Role,
          as: "roles",
          through: {
            attributes: [],
          },
          include: {
            model: Menu,
            as: "menus",
            through: {
              attributes: [],
            },
          },
        },
      });
      // 提取所有菜单
      const menuAll = user.roles.reduce((acc, role) => {
        return [...acc, ...role.menus];
      }, []);

      const menus = arrayToTree(
        [...new Set(menuAll.map((menu) => menu.id))].map((menuId) =>
          menuAll.find((menu) => menu.id === menuId)
        )
      );

      success(res, "查询成功", setPermission(menus));
    } catch (error) {
      next(error);
    }
  }
}

// 设置 permission 权限
function setPermission(menus) {
  return menus.map((item) => {
    item.permission = [];
    if (item.children) {
      if (item.children[0].menuType === 1) {
        item.permission = item.children.map((v) => v.name);
        delete item.children;
      } else {
        item.children = setPermission(item.children);
      }
    }
    return item;
  });
}
// 数据过滤
function filterData(data) {
  const nowData = {
    username: data.username,
    password: data.password,
    fullName: data.fullName,
    phone: data.phone,
    avatarUrl: data.avatarUrl,
    gender: data.gender,
    email: data.email,
    status: data.status,
  };

  return Object.fromEntries(
    Object.entries(nowData).filter(
      (item) => item[1] !== "" && item[1] !== void 0
    )
  );
}

async function getRoleIdByCode(codeList) {
  try {
    const roles =
      (await Role.findAll({
        attributes: [["id", "roleId"]],
        where: {
          code: {
            [Op.or]: codeList,
          },
        },
      })) || [];

    return roles.map((role) => role.toJSON());
  } catch (error) {
    next(error);
  }
}

module.exports = new UserController();
